/*
 * Created on Mar 30, 2004
 *
 * To change the template for this generated file go to
 * Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
 */
package littlecyberwar.ui;

import javax.swing.JPanel;
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.event.*; 
import javax.swing.*;
import javax.swing.border.*;

import littlecyberwar.tool.*;
import littlecyberwar.util.*;
import littlecyberwar.model.*;
import ModuleBuilder.model.*;

/**
 * @author Milton  Soong
 *
 * To change the template for this generated type comment go to
 * Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
 * 
 * This class should be a singleton
 */
public class ProfileCardPanel extends JPanel implements ChangeListener {
	public final static String _NO_PROFILE_SELECTED="NOPROF".intern();
	private final static String _resetDistanceStr = "0.0".intern();
	
	private CardLayout profilePanelCard;
	private UnitModel currUnit;		// current selected unit
	private ProfilePanel currProfilePanel;
	private HashMap allProfiles = new HashMap(1);
	private static ProfileCardPanel singleton;
	private boolean setUnitInProgress;	// need flag for stateChanged code to ignore
										// value change when setUnit is in progress
	private boolean modelChangeInProgress; // means this is from the unitAttributeCmd 
										// so DO NOT generate another command to avoid infinite loop
	private InternalCmdFacade icmd;
	
	public static ProfileCardPanel getInstance() {
		return (singleton);
	}
	
	public ProfileCardPanel() {
	  profilePanelCard = new CardLayout();
	  this.setLayout(profilePanelCard);
	  JPanel dummyPanel = new JPanel();	// to be used when nothing is selected.
	  this.add(dummyPanel, _NO_PROFILE_SELECTED);
	  singleton = this;
	  icmd = InternalCmdFacade.getInstance();
	}

	public CardLayout getProfilePanelCard() {
	   return ( profilePanelCard );
	 }

	public void add( ProfilePanel profileIn, String nameIn ){
		super.add(profileIn, nameIn);
		allProfiles.put(nameIn, profileIn);
	}
	/*
	 * This is called when a unit is selected, and the unit's modifiable
	 * attributes needs to be set into the matching profilePanel.
	 * 
	 * The unit id is also kept around.
	 */
	public void setUnit( UnitModel unitIn ) {
		setUnitInProgress = true;
		currUnit = unitIn;
		UnitProfileModel profMod = unitIn.getProfileModel();
		
		if ( profMod != null ){
			String profName = profMod.getName();

			ProfilePanel currProf = (ProfilePanel)allProfiles.get(profName);
			currProf.setUnitNameValueLabel(currUnit.getName());
			
			// now we need to find all the unit's changeable attributes, and then 
			// set them into the panel
			HashMap allValues = unitIn.getRangeValue();
			if ( allValues != null ) {				
				// there is at least one value that's variable
				Iterator it = allValues.entrySet().iterator();
				while(it.hasNext()){
					Map.Entry e = (Map.Entry)it.next();
					String attribName = (String)e.getKey();
					
					// check for special name for distance moved
					if ( attribName.equals(Util._elementAttribDistanceMoved)){
						Double d = (Double)e.getValue();
						String distanceText = MultiSelectMouseHandler.df.format(d);
						JLabel l = currProf.lookupDistanceMovedLabel();
						synchronized (this) {
							l.setText(distanceText);
						}	
					} else {					
						Integer attribVal = (Integer)e.getValue();
						// Debug.out("attribName= "+ attribName);
						SpinnerNumberModel spinner = currProf.lookupAttributeSpinner(attribName);
						// need to synchronize in case more than one user attmpt to change at once
						synchronized (this) {
							spinner.setValue(attribVal);
						}
					}	
				}
			}
			currProfilePanel = (ProfilePanel)allProfiles.get(profName);
			profilePanelCard.show(this, profName);
		}
		setUnitInProgress = false;
	}
	
	public void noUnitSelected() {
		currProfilePanel = null;
		profilePanelCard.show(this, _NO_PROFILE_SELECTED);
	}
	
	public UnitModel getUnit() {
		return ( currUnit );
	}
	
	/* 
	 * called here when some spinner have changed
	 * when this is called then by definition is done by the current unit. 
	 * and then generate a unitAttributeCmd
	 */
	public void stateChanged(ChangeEvent e) {
		if ( (setUnitInProgress == false) && (modelChangeInProgress == false) ){			
			JSpinner source = (JSpinner)e.getSource();
			String name = currProfilePanel.lookupAttributeNameFromSpinner(source);
			Integer val = (Integer)source.getValue();
			// Debug.out(currUnit.getName() + " has just changed the attribute: " + name);
			UnitAttributeCommand cmd = new UnitAttributeCommand(currUnit.getId(), name, val);
			cmd.setPlayerName(Players.getSelfName());
			icmd.addCmd(cmd);
		}
	}
	
	/**
	 * Make sure when this is called the stateChanged code does NOT get executed
	 * (Since that would just generate loops of cmds to ea. side to change attribute)
	 * 
	 * @param unitIdIn
	 * @param attribName
	 * @param val
	 */
	public void UnitAttributeUpdated( Integer unitIdIn, String attribName, Integer val ){
		if ( (currUnit != null) && (currProfilePanel != null) ){
			if ( currUnit.getId().equals(unitIdIn)){
				modelChangeInProgress = true;
				SpinnerNumberModel spinner = currProfilePanel.lookupAttributeSpinner(attribName);
				
				// need to synchronize in case more than one user attmpt to change at once
				synchronized (this) {
					spinner.setValue(val);
				}	
				modelChangeInProgress = false;			
			}
		}
		return;
	}

	// for double value only (for now just the distance moved field
	public void UnitDistanceAttributeUpdated( Integer unitIdIn, String attribName, Double val ){
		if ( (currUnit != null ) && (currProfilePanel != null) ){
			if ( currUnit.getId().equals(unitIdIn)){
				modelChangeInProgress = true;
				JLabel l = currProfilePanel.lookupDistanceMovedLabel();
				String distanceText = MultiSelectMouseHandler.df.format(val);
				//Debug.out("distanceText= "+ distanceText);
				// need to synchronize in case more than one user attmpt to change at once
				synchronized (this) {
					l.setText(distanceText);
				}	
				modelChangeInProgress = false;			
			}
		}
		return;
	}
	
	public void resetDistanceAttribute() {
		if ( currProfilePanel != null ){
			modelChangeInProgress = true;
			JLabel l = currProfilePanel.lookupDistanceMovedLabel();
			synchronized (this) {
				l.setText(_resetDistanceStr);
			}	
			modelChangeInProgress = false;			
			
		}
	}

}
